package com.idea.plugin.core.resolver;

import com.idea.plugin.core.constant.CommonConstant;
import com.idea.plugin.core.domain.dto.JavaClassDTO;
import com.idea.plugin.core.domain.dto.JavaImportDTO;
import com.idea.plugin.core.domain.dto.JavaMethodDTO;
import com.idea.plugin.core.domain.dto.JavaMockClassInfoDTO;
import com.idea.plugin.core.domain.dto.JavaParameterDTO;
import com.idea.plugin.core.domain.info.JavaClassInfo;
import com.idea.plugin.core.handler.FullNameHandle;
import com.idea.plugin.core.handler.MockClassInfoHandle;
import com.idea.plugin.core.helper.JavaClassHelper;
import com.idea.plugin.core.helper.StringUtils;
import com.idea.plugin.core.logging.Log;
import com.idea.plugin.core.logging.SystemStreamLog;
import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaSource;
import com.thoughtworks.qdox.model.JavaType;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 构建测试类
 *
 * @author chenhx
 * @version BuildClassImpl.java, v 0.1 2019-06-10 15:58 chenhx
 */
public class UnitTestingClassResolver {
    private static Log log = new SystemStreamLog();

    /**
     * 生成测试类
     *
     * @param javaClassInfo java类信息
     * @return true-生成成功，false-生成失败
     * @throws IOException IO异常
     */
    public static JavaClassDTO build(JavaClassInfo javaClassInfo) throws IOException {

        // 解析java文件信息
        resolveJavaClassInfo(javaClassInfo);

        // 验证是否跳过单测生成
        boolean verify = skipTesting(javaClassInfo);
        if (verify) {
            return null;
        }

        JavaClass javaClass = javaClassInfo.getJavaClass();
        log.info("当前正在构建类：" + javaClass);

        //封装基本的数据
        JavaClassDTO javaClassDTO = wrapBaseInfo(javaClassInfo);

        //设置mock的信息
        List<JavaMockClassInfoDTO> javaMockClassInfoDTOList = MockClassInfoHandle.getMockClass(javaClass, javaClassInfo);
        //需要引入的mcok类
        javaClassDTO.setJavaMockClassInfoDTOList(javaMockClassInfoDTOList);

        //设置方法，属性
        List<JavaMethodDTO> javaMethodDTOList = UnitTestingMethodResolver.build(javaClass, javaClassInfo);
        javaClassDTO.setJavaMethodDTOList(javaMethodDTOList);

        //获取导入的包 - 处理导入的包
        Map<String, Set<String>> implementsJavaPackageMap = javaClassInfo.getImportJavaPackageMap();
        List<JavaImportDTO> javaImportDTOList = FullNameHandle.handleImport(implementsJavaPackageMap);
        javaClassDTO.setJavaImportDTOList(javaImportDTOList);

        //处理测试类的参数，需要导入的包
        //遍历方法
        for (JavaMethodDTO javaMethodDTO : javaMethodDTOList) {
            //遍历参数
            List<JavaParameterDTO> javaParameterDTOList = javaMethodDTO.getJavaParameterDTOList();
            for (JavaParameterDTO javaParameterDTO : javaParameterDTOList) {
                String type = javaParameterDTO.getType();
                if (implementsJavaPackageMap.containsKey(type)) {
                    //包含该类型
                    Set<String> types = implementsJavaPackageMap.get(type);
                    //有多个简称，使用全名
                    if (types.size() > 1) {
                        //设置全名
                        javaParameterDTO.setType(javaParameterDTO.getFullyType());
                    }
                }
            }
        }

        log.debug("构建的类信息：" + javaClassDTO);
        return javaClassDTO;
    }

    /**
     * 解析java文件
     *
     * @param javaClassInfo
     */
    private static void resolveJavaClassInfo(JavaClassInfo javaClassInfo) {
        String sourceCode = javaClassInfo.getSourceCode();
        JavaSource javaSource = JavaClassHelper.javaProjectBuilder.addSource(new StringReader(sourceCode));
        javaClassInfo.setJavaSource(javaSource);
        javaClassInfo.setPackageName(javaSource.getPackageName());
        List<JavaClass> classes = javaSource.getClasses();
        if (classes == null || classes.isEmpty()) {
            return;
        }
        JavaClass javaClass = classes.get(0);
        javaClassInfo.setJavaClass(javaClass);
        javaClassInfo.setTypeName(javaClass.getName());
        javaClassInfo.setTestAbsolutePath(javaClassInfo.getBaseDir() + CommonConstant.JAVA_TEST_SRC + javaClassInfo.getPackageName().replace(".", "/") + "/" + javaClassInfo.getTypeName() + CommonConstant.TEST_CLASS_SUFFIX + ".java");
        //设置首字母小写的类名  被测试的类名
        javaClassInfo.setModelNameLowerCamel(StringUtils.strConvertLowerCamel(javaClassInfo.getTypeName()));
    }

    private static JavaClassDTO wrapBaseInfo(JavaClassInfo javaClassInfo) {
        //模板类信息
        JavaClassDTO javaClassDTO = new JavaClassDTO();
        //构建信息
        javaClassDTO.setDate(CommonConstant.DATE);
        javaClassDTO.setAuthor(CommonConstant.CONFIG_ENTITY.getAuthor());
        javaClassDTO.setModelNameUpperCamel(javaClassInfo.getTypeName());
        //设置首字母小写的类名  被测试的类名
        javaClassDTO.setModelNameLowerCamel(javaClassInfo.getModelNameLowerCamel());
        javaClassDTO.setModelNameUpperCamelTestClass(javaClassInfo.getTypeName() + CommonConstant.TEST_CLASS_SUFFIX);
        javaClassDTO.setModelNameLowerCamelTestClass(StringUtils.strConvertLowerCamel(javaClassInfo.getTypeName() + CommonConstant.TEST_CLASS_SUFFIX));
        javaClassDTO.setPackageName(javaClassInfo.getPackageName());
        return javaClassDTO;
    }

    /**
     * 是否跳过类的测试生成
     *
     * @return 返回是否跳过类的测试生成，true-跳过
     */
    private static boolean skipTesting(JavaClassInfo javaClassInfo) {
        final JavaClass javaClass = javaClassInfo.getJavaClass();
        if (javaClassInfo.getJavaClass() == null) {
            log.error("未查询到该类，请确保项目包中有该类，类名：" + javaClassInfo.getFullyTypeName());
            return true;
        }
        if (javaClass.isInterface()) {
            log.info("跳过接口：" + javaClass);
            return true;
        }
        if (javaClass.isEnum()) {
            log.info("跳过枚举：" + javaClass);
            return true;
        }
        if (javaClass.isAbstract()) {
            log.info("跳过抽象类：" + javaClass);
            return true;
        }
        if (javaClass.isPrivate()) {
            log.info("跳过私有类：" + javaClass);
            return true;
        }
        return false;
    }

    /**
     * 获取导入的包名
     *
     * @param cls
     * @return
     */
    private static List<JavaImportDTO> getJavaImplementsDTOList(JavaClass cls) {
        List<JavaType> javaTypeList = cls.getImplements();
        List<JavaImportDTO> javaImportDTOList = new ArrayList<>();
        for (JavaType javaType : javaTypeList) {
            JavaImportDTO javaImportDTO = new JavaImportDTO();
            javaImportDTO.setType(javaType.getFullyQualifiedName());
            javaImportDTOList.add(javaImportDTO);
        }
        return javaImportDTOList;
    }

}
